/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * CorrelationHeatmap.java
 *
 * Created on 10.03.2010, 10:08:01
 */
package GUI.iFrames;

import java.awt.BasicStroke;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Vector;

import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.annotations.XYTextAnnotation;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.SymbolAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.entity.ChartEntity;
import org.jfree.chart.entity.XYItemEntity;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYBubbleRenderer;
import org.jfree.data.statistics.Statistics;
import org.jfree.data.xy.DefaultXYZDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.util.ShapeUtilities;

import GUI.BaseFrame;
import GUI.iFrames.DataSourceComponents.DataSourcesInternalFrame;

/**
 * 
 * @author Bunkowski
 */
public class CorrelationBubblePlot extends javax.swing.JInternalFrame implements MouseListener, ChartMouseListener,
		MouseWheelListener, MouseMotionListener {

	public static final long serialVersionUID = 1L;

	private XYPlot heatmapPlot;
	private NumberAxis yaxis;
	private NumberAxis xaxis;
	private String[] names;
	private DefaultXYZDataset imsdds;
	private DataSourcesInternalFrame dsif;
	private ChartInternalFrame cif1, cif2;
	private CorrelationLinePlotInternalFrame cifCor;
	private Point2D panStartPoint;
	private ChartPanel cp;

	/** Creates new form CorrelationHeatmap */
	public CorrelationBubblePlot(DefaultXYZDataset imsdds, String[] names, DataSourcesInternalFrame dsif) {
		this.names = names;
		this.imsdds = imsdds;
		this.dsif = dsif;
		initComponents();
		showCorrelationHetamp(imsdds, names);
	}

	private void showCorrelationHetamp(DefaultXYZDataset imsdds, String[] names) {

		XYBubbleRenderer xybr = new XYBubbleRenderer();
		xybr.setBaseOutlineStroke(new BasicStroke(0));

		// xybr.setDataBoundsIncludesVisibleSeriesOnly(true);

		yaxis = new SymbolAxis("", names);
		xaxis = new SymbolAxis("", names);

		xaxis.setVerticalTickLabels(true);

		heatmapPlot = new XYPlot(imsdds, xaxis, yaxis, xybr);

		if (showLabelsCheckBoxMenuItem.isSelected()) {
			showLabels();
		} else {
			heatmapPlot.clearAnnotations();
		}

		center.removeAll();
		JFreeChart chart = new JFreeChart(heatmapPlot);
		chart.setTitle("Correlation");
		cp = new ChartPanel(chart);

		cp.addMouseWheelListener(this);
		cp.addChartMouseListener(this);
		cp.addMouseMotionListener(this);
		cp.addMouseListener(this);
		center.add(cp);

	}

	private void showLabels() {
		DecimalFormat df = new DecimalFormat("0.00");
		double correlationDisplayCuttoff = 0.1;
		int snr = imsdds.getSeriesCount();

		for (int i = 0; i < snr; i++) {
			int itemsinseries = imsdds.getItemCount(i);
			for (int j = 0; j < itemsinseries; j++) {
				if (imsdds.getZValue(i, j) > correlationDisplayCuttoff) {
					String value = df.format(imsdds.getZValue(i, j));
					double x = imsdds.getXValue(i, j);
					double y = imsdds.getYValue(i, j);
					XYTextAnnotation xyt = new XYTextAnnotation(value, x, y);
					heatmapPlot.addAnnotation(xyt);
				}
			}
		}
	}

	/**
	 * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The
	 * content of this method is always regenerated by the Form Editor.
	 */
	private void initComponents() {

		center = new javax.swing.JPanel();
		jMenuBar1 = new javax.swing.JMenuBar();
		optionsMenu = new javax.swing.JMenu();
		showLabelsCheckBoxMenuItem = new javax.swing.JCheckBoxMenuItem();

		setClosable(true);
		setIconifiable(true);
		setMaximizable(true);
		setResizable(true);
		setTitle("Correlation analysis");

		center.setLayout(new javax.swing.BoxLayout(center, javax.swing.BoxLayout.Y_AXIS));

		optionsMenu.setText("Options");

		showLabelsCheckBoxMenuItem.setSelected(true);
		showLabelsCheckBoxMenuItem.setText("show labels");
		showLabelsCheckBoxMenuItem.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				showLabelsCheckBoxMenuItemActionPerformed(evt);
			}
		});
		optionsMenu.add(showLabelsCheckBoxMenuItem);

		jMenuBar1.add(optionsMenu);

		setJMenuBar(jMenuBar1);

		javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
		getContentPane().setLayout(layout);
		layout.setHorizontalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addComponent(
				center, javax.swing.GroupLayout.DEFAULT_SIZE, 394, Short.MAX_VALUE));
		layout.setVerticalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addComponent(
				center, javax.swing.GroupLayout.DEFAULT_SIZE, 273, Short.MAX_VALUE));

		pack();
	}// </editor-fold>//GEN-END:initComponents

	private void showLabelsCheckBoxMenuItemActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_showLabelsCheckBoxMenuItemActionPerformed
		if (showLabelsCheckBoxMenuItem.isSelected()) {
			showLabels();
		} else {
			heatmapPlot.clearAnnotations();
		}
	}// GEN-LAST:event_showLabelsCheckBoxMenuItemActionPerformed

	// Variables declaration - do not modify//GEN-BEGIN:variables
	private javax.swing.JPanel center;
	private javax.swing.JMenuBar jMenuBar1;
	private javax.swing.JMenu optionsMenu;
	private javax.swing.JCheckBoxMenuItem showLabelsCheckBoxMenuItem;

	// End of variables declaration//GEN-END:variables

	public void mousePressed(MouseEvent e) {
		if (e.getButton() == 2) {
			cp.setDomainZoomable(false);
			cp.setRangeZoomable(false);
			Rectangle2D dataArea = cp.getScreenDataArea();
			Point2D point = e.getPoint();
			if (dataArea.contains(point)) {
				this.panStartPoint = point;
			}
		}

	}

	public void mouseReleased(MouseEvent e) {

		this.panStartPoint = null;
		cp.setDomainZoomable(true);
		cp.setRangeZoomable(true);

	}

	public void mouseDragged(MouseEvent e) {
		if (this.panStartPoint != null) {
			Rectangle2D scaledDataArea = this.cp.getScreenDataArea();

			this.panStartPoint = ShapeUtilities.getPointInRectangle(this.panStartPoint.getX(),
					this.panStartPoint.getY(), scaledDataArea);
			Point2D panEndPoint = ShapeUtilities.getPointInRectangle(e.getX(), e.getY(), scaledDataArea);

			// horizontal pan

			XYPlot hvp = cp.getChart().getXYPlot();
			ValueAxis xAxis = hvp.getDomainAxis();

			if (xAxis != null) {
				double translatedStartPoint = xAxis.java2DToValue((float) this.panStartPoint.getX(), scaledDataArea,
						hvp.getDomainAxisEdge());
				double translatedEndPoint = xAxis.java2DToValue((float) panEndPoint.getX(), scaledDataArea,
						hvp.getDomainAxisEdge());
				double dX = translatedStartPoint - translatedEndPoint;

				double oldMin = xAxis.getLowerBound();
				double newMin = oldMin + dX;

				double oldMax = xAxis.getUpperBound();
				double newMax = oldMax + dX;

				xAxis.setLowerBound(newMin);
				xAxis.setUpperBound(newMax);
			}

			// vertical pan (1. Y-Axis)

			XYPlot vvp = cp.getChart().getXYPlot();
			ValueAxis yAxis = vvp.getRangeAxis();

			if (yAxis != null) {
				double translatedStartPoint = yAxis.java2DToValue((float) this.panStartPoint.getY(), scaledDataArea,
						vvp.getRangeAxisEdge());
				double translatedEndPoint = yAxis.java2DToValue((float) panEndPoint.getY(), scaledDataArea,
						vvp.getRangeAxisEdge());
				double dY = translatedStartPoint - translatedEndPoint;

				double oldMin = yAxis.getLowerBound();
				double newMin = oldMin + dY;

				double oldMax = yAxis.getUpperBound();
				double newMax = oldMax + dY;

				yAxis.setLowerBound(newMin);
				yAxis.setUpperBound(newMax);
			}

			// for the next time
			this.panStartPoint = panEndPoint;
		}
	}

	public void chartMouseMoved(ChartMouseEvent arg0) {
	}

	public void mouseClicked(MouseEvent e) {
	}

	public void mouseEntered(MouseEvent e) {
	}

	public void mouseExited(MouseEvent e) {
	}

	public void mouseMoved(MouseEvent e) {
	}

	public void mouseWheelMoved(MouseWheelEvent e) {
		if (!(e.isAltDown() || e.isControlDown() || e.isShiftDown())) {
			XYPlot plot = cp.getChart().getXYPlot();
			double xViewSize = plot.getDomainAxis().getUpperBound() - plot.getDomainAxis().getLowerBound();

			double yViewSize = plot.getRangeAxis().getUpperBound() - plot.getRangeAxis().getLowerBound();

			if (e.getWheelRotation() > 0) {
				xViewSize *= -1;
				yViewSize *= -1;
			}

			plot.getDomainAxis().setUpperBound(plot.getDomainAxis().getUpperBound() - xViewSize / 20);
			plot.getDomainAxis().setLowerBound(plot.getDomainAxis().getLowerBound() + xViewSize / 20);
			plot.getRangeAxis().setUpperBound(plot.getRangeAxis().getUpperBound() - yViewSize / 20);
			plot.getRangeAxis().setLowerBound(plot.getRangeAxis().getLowerBound() + yViewSize / 20);
		}
	}

	public void chartMouseClicked(ChartMouseEvent arg0) {
		ChartEntity ce = arg0.getEntity();
		if (ce instanceof XYItemEntity) {
			XYItemEntity xi = (XYItemEntity) ce;

			int series = xi.getSeriesIndex();
			int item = xi.getItem();

			String xSubstance = names[imsdds.getX(series, item).intValue()];
			String ySubstance = names[imsdds.getY(series, item).intValue()];
			// double z = imsdds.getZValue(series, item);

			if (arg0.getTrigger().getButton() == 1) {

				if (cif1 != null) {
					if (cif1.isClosed()) {
						cif1 = null;
					}
				}
				if (cif1 == null) {
					cif1 = new ChartInternalFrame(xSubstance, dsif.getColumnForSubstance(xSubstance),
							dsif.getSelectedClassColumn(), dsif.getSelectedLabelColumn());
					cif1.setBounds(600, 0, 600, 400);
					BaseFrame.applyFrame(cif1);
					cif1.moveToFront();
				} else {
					cif1.setData(xSubstance, dsif.getColumnForSubstance(xSubstance), dsif.getSelectedClassColumn(),
							dsif.getSelectedLabelColumn());
				}

				if (cif2 != null) {
					if (cif2.isClosed()) {
						cif2 = null;
					}
				}
				if (cif2 == null) {
					cif2 = new ChartInternalFrame(ySubstance, dsif.getColumnForSubstance(ySubstance),
							dsif.getSelectedClassColumn(), dsif.getSelectedLabelColumn());
					cif2.setBounds(0, 0, 600, 400);
					BaseFrame.applyFrame(cif2);
					cif2.moveToFront();
				} else {
					cif2.setData(ySubstance, dsif.getColumnForSubstance(ySubstance), dsif.getSelectedClassColumn(),
							dsif.getSelectedLabelColumn());
				}
			}
			if (arg0.getTrigger().getButton() == 2) {
				Vector<Double> xSubstanceValues = dsif.getColumnForSubstance(xSubstance);
				Vector<Double> ySubstanceValues = dsif.getColumnForSubstance(ySubstance);
				Vector<String> classLabels = dsif.getSelectedClassColumn();

				ArrayList<String> categories = new ArrayList<String>();

				if (classLabels == null) {
					classLabels = new Vector<String>();
					for (int i = 0; i < ySubstanceValues.size(); i++) {
						classLabels.add("Data Points");
					}
				}

				for (String s : classLabels) {
					if (!categories.contains(s)) {
						categories.add(s);
					}
				}

				XYSeriesCollection sc = new XYSeriesCollection();

				XYSeries allInOne = new XYSeries("allInOne");
				for (int i = 0; i < xSubstanceValues.size(); i++) {
					allInOne.add(xSubstanceValues.get(i), ySubstanceValues.get(i));
				}

				Double[] xData = new Double[xSubstanceValues.size()];
				Double[] yData = new Double[ySubstanceValues.size()];

				for (int i = 0; i < xSubstanceValues.size(); i++) {
					Double double1 = xSubstanceValues.elementAt(i);
					xData[i] = double1;
				}

				for (int i = 0; i < ySubstanceValues.size(); i++) {
					Double double1 = ySubstanceValues.elementAt(i);
					yData[i] = double1;
				}

				double[] interceptSlope = Statistics.getLinearFit(xData, yData);
				double intercept = interceptSlope[0];
				double slope = interceptSlope[1];

				XYSeries line = new XYSeries("Linear fit");

				// line.add(0, intercept);
				line.add(allInOne.getMinX(), slope * allInOne.getMinX() + intercept);
				line.add(allInOne.getMaxX(), slope * allInOne.getMaxX() + intercept);
				sc.addSeries(line);

				for (String category : categories) {
					XYSeries s = new XYSeries(category);
					for (int i = 0; i < xSubstanceValues.size(); i++) {
						if (classLabels.get(i).equals(category)) {
							s.add(xSubstanceValues.get(i), ySubstanceValues.get(i));
						}
					}
					sc.addSeries(s);
				}

				if (cifCor != null) {
					if (cifCor.isClosed()) {
						cifCor = null;
					}
				}
				if (cifCor == null) {
					cifCor = new CorrelationLinePlotInternalFrame();
					cifCor.showXYChart(sc, xSubstance, ySubstance);
					cifCor.setBounds(0, 0, 600, 400);
					BaseFrame.applyFrame(cifCor);
					cifCor.moveToFront();
				} else {
					cifCor.showXYChart(sc, xSubstance, ySubstance);
				}
			}
		}
	}

}
